Skip to content

feat: plugin discovery (search npm/GitHub for compatible plugins)#2

Merged
kreneskyp merged 3 commits into
mainfrom
feat/plugin-discovery
Jun 28, 2026
Merged

feat: plugin discovery (search npm/GitHub for compatible plugins)#2
kreneskyp merged 3 commits into
mainfrom
feat/plugin-discovery

Conversation

@kreneskyp

Copy link
Copy Markdown
Contributor

Summary

Adds a zero-dependency plugin-discovery module (src/search.ts) that searches npm and GitHub for plugins compatible with a host application, plus its full spec-driven artifact set.

Public API

  • searchPlugins() — query npm + GitHub by tag/keyword, dedupe and rank candidates by signal, return host-verified compatible plugins.
  • createPluginSearch() — factory binding injectable transports (npm/GitHub fetchers) and a TTL cache for reuse.
  • createTtlCache() — small in-memory TTL cache for discovery results.
  • sourceToInstallInput() — map a discovered source to an install input.

Behavior

  • Host-driven verification — the host decides compatibility; discovery only gathers and ranks candidates.
  • GitHub rate-limit handling — detects and surfaces rate-limit responses gracefully rather than throwing.
  • Zero runtime dependencies; transports are injectable for deterministic testing.
  • 100% covered (src/search.ts + tests/search.test.ts); the full src/** coverage gate remains at 100% on this branch.

Spec-driven artifacts

  • US-003 — discover plugins by tag.
  • FR-008..FR-012 — candidate search, compatibility verification, discovery cache, GitHub rate-limit, source-to-install-input.
  • NFR-005 — injectable discovery transport.
  • SpecReviews — base, failure-domain, ears-conformance, scope-boundary, index.
  • Plan-001-plugin-discovery — plan + Task-001..008.
  • Edits to spec.md, the usecase/functional/non-functional indexes, NFR-001, NFR-003, and spec/tests.md.

Gates

  • tsc --noEmit → clean
  • vitest run → 72 passed
  • test:coverage (full src/**) → 100% statements / branches / functions / lines
  • eslint src/** tests/** → clean
  • prettier --check → clean
  • quire validate → 0 errors

Reconciliation note

This PR shares spec.md / NFR-003 edits and Test Case numbers (TC-022..TC-054) with the concurrent feat/npm-source-resolution PR. npm lands first; this branch's overlapping spec.md / NFR-003 / TC numbering will be reconciled at the second merge.

🤖 Generated with Claude Code

@kreneskyp kreneskyp requested a review from a team as a code owner June 27, 2026 22:13
Comment thread tests/search.test.ts Fixed
Comment thread tests/search.test.ts Fixed
Comment thread tests/search.test.ts Fixed
Add a zero-dependency plugin-discovery module (src/search.ts) that
searches npm and GitHub for plugins compatible with a host application.

Public API:
- searchPlugins(): query npm + GitHub by tag/keyword, dedupe and rank
  candidates by signal, and return host-verified compatible plugins.
- createPluginSearch(): factory that binds injectable transports
  (npm/GitHub fetchers) and a TTL cache for reuse.
- createTtlCache(): small in-memory TTL cache for discovery results.
- sourceToInstallInput(): map a discovered source to an install input.

Behavior:
- Host-driven verification: the host decides compatibility; discovery
  only gathers and ranks candidates.
- GitHub rate-limit handling: detects and surfaces rate-limit responses
  gracefully rather than throwing.
- Zero runtime dependencies; transports are injectable for testing.
- 100% covered (src/search.ts + tests/search.test.ts); full src/** gate
  remains at 100%.

Also adds the spec-driven artifacts: US-003, FR-008..FR-012, NFR-005,
SpecReviews (base, failure-domain, ears-conformance, scope-boundary,
index), and plan/Plan-001-plugin-discovery/**, plus edits to spec.md,
the usecase/functional/non-functional indexes, NFR-001, NFR-003, and
spec/tests.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… URLs

Address SR-005 gap-analysis follow-ups on src/search.ts (TDD: failing test
first, then fix). None were merge-blockers; the first two are real
(privacy + memory) and one is a spec/code divergence.

- FND-002 (privacy + spec divergence): cacheKey keyed on token presence
  (auth/anon), colliding distinct tokens. Fold a stable non-secret token-id
  (first 8 hex of SHA-256 via node:crypto) into the key per FR-010 §Behavior;
  raw token never enters the key (FR-008-CON-2). Test TC-055.
- FND-003 (memory): default cacheMax to 256 in createPluginSearch so the TTL
  cache is bounded; explicit override still honored. Tests TC-056, TC-060.
- FND-004 (in-CDN path traversal): reject registry-supplied name/fullName whose
  path segments contain ".." or control chars before building the manifest URL;
  drop the candidate without fetching. FR-009-CON-1. Test TC-057.
- FND-005: parseRate treats a non-finite header parse as "no rate info"
  (undefined) instead of surfacing NaN; cache hits now return a shallow clone
  rather than the shared SearchResponse reference. Tests TC-058, TC-059.
- FND-001 (process): flip Plan-001 Task-001..007 status todo -> done
  (Task-008 publish stays pending).

Spec: add FR-009-AC-9/-CON-1, FR-010-AC-8..10 (+cacheMax input), FR-011-AC-6,
and the TC-055..TC-060 matrix rows. src/search.ts stays at 100% coverage;
tsc/eslint/prettier clean; quire validate clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread tests/search.test.ts Fixed
… + fix CodeQL

Integrate main's npm-source-resolution (PR #3) and git-security (PR #8) work
with the plugin-discovery feature (search.ts). Resolved conflicts in
spec/spec.md, spec/non-functional/NFR-003, and spec/tests.md so both main's
npm/git content and the discovery content survive.

Renumber the discovery test cases off main's TC-001..TC-031 block: the
contiguous discovery block TC-022..TC-060 shifts +10 to TC-032..TC-070
(uniform map, relative order preserved). Updated every occurrence across
tests.md (FR/NFR coverage, Test Index, Constraint Boundary, Error-Path,
Edge Cases, coverage-summary prose), the discovery FR files (FR-008..FR-012),
and the TC tags in tests/search.test.ts. FR-004 (main) left intact.

Fix 4 HIGH CodeQL js/incomplete-url-substring-sanitization alerts in
tests/search.test.ts by replacing url.includes("<host>.com") routing checks
with strict `new URL(url).host === "<host>"` comparisons.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kreneskyp kreneskyp merged commit b003a58 into main Jun 28, 2026
5 checks passed
@kreneskyp kreneskyp mentioned this pull request Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants